package Settings;

import java.awt.Color;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Observable;

import javax.swing.JColorChooser;

import com.thoughtworks.xstream.XStream;

/**
 * This class contains all settings for visualisation in GeneScapes. It contains
 * all general settings as well as the track specific ones.
 * 
 * @author Stefan Lorenz<br>
 * <br>
 *         26.11.2012
 */
@SuppressWarnings("serial")
public class Settings extends Observable implements Serializable {

	/**
	 * Colorchooser to choose color
	 */
	private JColorChooser colorChooser;
	/**
	 * Array containing the track settings for each single track
	 */
	private FeatureAndWiggleSettings[] tracksettings;
	/**
	 * Array containing the six frame setting for each single track
	 */
	private SixFrameSettings[] sixFrameSettings;
	/**
	 * Array containing the colors of the found motifs in the sequence
	 */
	private Color[] motifColor;
	/**
	 * Array containing the sequence setting for each single track
	 */
	private SequenceSettings[] sequenceSettings;
	/**
	 * The background color of the browser
	 */
	private Color backgroundColor;
	/**
	 * The color of all label
	 */
	private Color labelingColor;
	/**
	 * The color of selected features
	 */
	private Color selectionColor;
	/**
	 * The y position of the position labels
	 */
	private int positionLabelSize;
	/**
	 * Is the browser in full screen mode?
	 */
	private boolean isFullScreen;
	/**
	 * Does the information window switch location by hovering?
	 */
	private boolean isInfoWindowLocationFixed;

	/**
	 * Constructor of standard settings
	 */
	public Settings() {




		this.colorChooser = new JColorChooser();

		this.tracksettings = new FeatureAndWiggleSettings[16];
		this.sequenceSettings = new SequenceSettings[16];

		this.sixFrameSettings = new SixFrameSettings[16];

		this.backgroundColor = Color.WHITE;
		this.labelingColor = Color.BLACK;
		this.selectionColor = Color.DARK_GRAY;

		this.motifColor = new Color[3];
		this.motifColor[0] = Color.RED;
		this.motifColor[1] = Color.RED;
		this.motifColor[2] = Color.RED;
		
		this.isInfoWindowLocationFixed = true;

		this.positionLabelSize = 12;

		for (int i = 0; i < this.getTracksettings().length; i++) {
			this.setTracksettings(new FeatureAndWiggleSettings(), i);
			this.setSequenceSettings(new SequenceSettings(), i);
			this.setSixFrameSettings(new SixFrameSettings(), i);
		}
		this.getTracksettings()[0].setReadWiggleShown(false);
		this.getTracksettings()[1].setReadWiggleShown(false);
	}

	/**
	 * Saves the Settings as a XML file
	 * 
	 * @param pathString
	 *            the path to store the settings
	 */
	public void saveSettings(String pathString) {
		if (!pathString.endsWith(".xml"))
			pathString += ".xml";
		XStream xstream = new XStream();

		xstream.alias("settings", Settings.class);
		String xml = xstream.toXML(this);
		try {
			BufferedWriter bw = new BufferedWriter(new FileWriter(new File(pathString)));
			bw.write(xml);
			bw.flush();
			bw.close();
			System.out.println("...settings saved.");
		}
		catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Load a settings XML file
	 * 
	 * @param file
	 *            file to load
	 * @return loaded Settings
	 */
	public Settings loadSettings(File file) throws Exception {
		XStream xstream = new XStream();
		xstream.alias("settings", Settings.class);
		Object object = xstream.fromXML(file);
		return (Settings) object;
	}

	/**
	 * Returns the colorchooser
	 * 
	 * @return colorchooser to select colors
	 */
	public JColorChooser getColorChooser() {
		return colorChooser;
	}

	/**
	 * Sets the colorchooser
	 * 
	 * @param colorChooser
	 *            colorchooser to choose colors
	 */
	public void setColorChooser(JColorChooser colorChooser) {
		this.colorChooser = colorChooser;
	}

	/**
	 * Returns the array with the track settings
	 * 
	 * @return array with track settings
	 */
	public FeatureAndWiggleSettings[] getTracksettings() {
		return tracksettings;
	}

	/**
	 * Sets track setting to the array by index
	 * 
	 * @param tracksettings
	 *            track settings to set
	 * @param index
	 *            track to load track setting to
	 */
	public void setTracksettings(FeatureAndWiggleSettings tracksettings, int index) {
		this.tracksettings[index] = tracksettings;
	}

	/**
	 * Returns an array with six frame settings
	 * 
	 * @return array with six frame settings
	 */
	public SixFrameSettings[] getSixFrameSettings() {
		return sixFrameSettings;
	}

	/**
	 * Sets a six frame setting to the array by index
	 * 
	 * @param sixFrameSettings
	 *            six frame setting to set
	 * @param index
	 *            index of the six frame setting
	 */
	public void setSixFrameSettings(SixFrameSettings sixFrameSettings, int index) {
		this.sixFrameSettings[index] = sixFrameSettings;
	}

	/**
	 * Returns the background color of the browser
	 * 
	 * @return the background color
	 */
	public Color getBackgroundColor() {
		return backgroundColor;
	}

	/**
	 * Sets the background color of the browser
	 * 
	 * @param backgroundColor
	 *            the background color
	 */
	public void setBackgroundColor(Color backgroundColor) {
		this.backgroundColor = backgroundColor;
	}

	/**
	 * Returns the color of the position labels
	 * 
	 * @return color of the labels
	 */
	public Color getLabelingColor() {
		return labelingColor;
	}

	/**
	 * Sets the color of the position labels
	 * 
	 * @param labelingColor
	 *            color of the labels
	 */
	public void setLabelingColor(Color labelingColor) {
		this.labelingColor = labelingColor;
	}

	/**
	 * Returns the color of selected features
	 * 
	 * @return color of selected features
	 */
	public Color getSelectionColor() {
		return selectionColor;
	}

	/**
	 * Sets the color of selected features
	 * 
	 * @param selectionColor
	 *            color of selected features
	 */
	public void setSelectionColor(Color selectionColor) {
		this.selectionColor = selectionColor;
	}

	/**
	 * Sets the color of a motif by index
	 * 
	 * @param motifColor
	 *            color of the motif
	 * @param index
	 *            index of motif
	 */
	public void setMotifColor(Color motifColor, int index) {
		this.motifColor[index] = motifColor;
	}

	/**
	 * Returns the color of a motif by index
	 * 
	 * @param index
	 *            index of the motif color
	 * @return color of the motif
	 */
	public Color getMotifColor(int index) {
		return motifColor[index];
	}

	/**
	 * Sets a sequence setting to the array by index
	 * 
	 * @param sequenceSettings
	 *            sequence setting to set
	 * @param i
	 *            index of the sequence setting
	 */
	public void setSequenceSettings(SequenceSettings sequenceSettings, int i) {
		this.sequenceSettings[i] = sequenceSettings;
	}

	/**
	 * Returns a sequence setting out of the array by index
	 * 
	 * @param i
	 *            index of the sequence setting
	 * @return sequence setting
	 */
	public SequenceSettings getSequenceSettings(int i) {
		return sequenceSettings[i];
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return super.toString();
	}

	/**
	 * Writes the settings to a file
	 * 
	 * @param filename
	 *            name of the file to save settings
	 * @param object
	 *            object to write
	 */
	public void serialize(String filename, Object object) {

		try {
			if (!filename.endsWith(".ser"))
				filename += ".ser";
			FileOutputStream file = new FileOutputStream(filename);
			ObjectOutputStream o = new ObjectOutputStream(file);
			o.writeObject(object);
			o.close();
			System.out.println("Settings saved: " + filename);
		}
		catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Load settings
	 * 
	 * @param file
	 *            file to load @
	 */
	public Object deserialize(File file) {
		try {
			FileInputStream fileInput = new FileInputStream(file);
			ObjectInputStream o = new ObjectInputStream(fileInput);
			Object object = (Settings) o.readObject();
			o.close();
			System.out.println("Loading settings: " + file.getAbsolutePath());
			return object;
		}
		catch (IOException e) {
			System.err.println("Can not load settings " + file.getAbsolutePath());
		}
		catch (ClassNotFoundException e) {
			System.err.println("Can not load settings " + file.getAbsolutePath());
		}
		catch (Exception e) {
			System.err.println("Can not load settings " + file.getAbsolutePath());
		}
		return null;
	}

	/**
	 * Sets the the full screen tag
	 * 
	 * @param isFullScreen
	 *            is browser in fullscreen?
	 */
	public void setFullScreen(boolean isFullScreen) {
		this.isFullScreen = isFullScreen;
	}

	/**
	 * Is browser in full screen mode?
	 * 
	 * @return full screen or not
	 */
	public boolean isFullScreen() {
		return isFullScreen;
	}

	/**
	 * Sets the size of the position labels
	 * 
	 * @param positionLabelSize
	 *            size of the labels
	 */
	public void setPositionLabelSize(int positionLabelSize) {
		this.positionLabelSize = positionLabelSize;
	}

	/**
	 * Returns the size of the position labels
	 * 
	 * @return the size of the positions labels
	 */
	public int getPositionLabelSize() {
		return positionLabelSize;
	}

	public boolean isInfoWindowLocationFixed() {
		return isInfoWindowLocationFixed;
	}

	public void setInfoWindowLocationFixed(boolean isInfoWindowLocationFixed) {
		this.isInfoWindowLocationFixed = isInfoWindowLocationFixed;
	}
}
